/******************************************************************************
 **
 **    LISA Confidential
 **
 **    Source Materials
 **
 **    (C) COPYRIGHT LISA 2008-2009
 **
 **
 **  File Name:      TransProcessInstancebyProcessInstanceCommand.java
 **  Description:
 **  Date:           2008-10-27
 **  Author:         LisaQian
 ******************************************************************************/
package com.ti.andon.workflow.command;

import java.util.Collection;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmContext;
import org.jbpm.command.Command;
import org.jbpm.taskmgmt.exe.PooledActor;
import org.jbpm.taskmgmt.exe.TaskInstance;

import com.ti.andon.workflow.WFConstants;

public class TransProcessInstancebyProcessInstanceCmd implements Command
{
	/**
	 * Serial Version ID.
	 */
	private static final long serialVersionUID = -5229527720139327665L;

	private static Log logger = LogFactory.getLog(TransProcessInstancebyProcessInstanceCmd.class);
	
	// the business key of the process instance requested
	String businessKey;
	// the process definition name of the process requested
	String processDefinitionName;
	// the transition name which the process instance transit
	String transitionName;
	// the user id
	Long actorId;
    // The comment added by the operator
	String comment;

	/**
	 * Constructor.
	 * */
	public TransProcessInstancebyProcessInstanceCmd(String businessKey, String processDefinitionName,
			String transitionName, Long actorId, String comment)
	{
		this.businessKey = businessKey;
		this.processDefinitionName = processDefinitionName;
		this.transitionName = transitionName;
		this.actorId = actorId;
		this.comment = comment;
	}

	/**
	 * Retrieves the destination node name of the specified task instance
	 * matching process definition name, the business key, actor id. And sets
	 * the variable to the task instance, triggers the transition.
	 * 
	 * @param jbpmContext
	 * @return The destination node name
	 */
	public Object execute(JbpmContext jbpmContext) throws Exception
	{
		TaskInstance taskInstance = null;
		String nextNodeName = null;
		if (null == businessKey)
		{
			logger.error("TransProcessInstancebyProcessInstanceCmd.execute() : businessKey can not be null!!!");
			throw new Exception("TransProcessInstancebyProcessInstanceCmd.execute() : businessKey can not be null!!!");
		}
		GetCurrentTaskInstancesCmd command = new GetCurrentTaskInstancesCmd(this.businessKey,
				this.processDefinitionName);
		boolean flag = false;
		try
		{
			Collection taskInstances = (Collection)command.execute(jbpmContext);
			if (null != taskInstances)
			{				
				Iterator iterTaskInstance = taskInstances.iterator();
				Iterator iterPooledActor = null;
				java.util.Set pooledActors = null;
				TaskInstance tempTaskInstance = null;
				while (iterTaskInstance.hasNext() && !flag)
				{
					tempTaskInstance = (TaskInstance) iterTaskInstance.next();
					if (tempTaskInstance.getActorId() != null && null != this.actorId
							&& tempTaskInstance.getActorId().equals(this.actorId.toString()))
					{
						flag = true;
						taskInstance = tempTaskInstance;
						break;
					}
					else
					{
						pooledActors = tempTaskInstance.getPooledActors();
						if (null != pooledActors)
						{
							iterPooledActor = pooledActors.iterator();
							// If no pooled actors, specify the default task instance. 
							if (!iterPooledActor.hasNext())
							{
								flag = true;
								taskInstance = tempTaskInstance;
							}
							// Else checks the pooled actors. 
							else
							{
								while (iterPooledActor.hasNext())
								{
									PooledActor actor = (PooledActor) iterPooledActor.next();
									if (null != actor && null != actor.getActorId() && null != this.actorId
											&& actor.getActorId().equals(this.actorId.toString()))
									{
										flag = true;
										taskInstance = tempTaskInstance;
										break;
									}
								}
							}
						}
					}
				}
			}

			if (flag)
			{
				if (null != this.actorId)
				{
					taskInstance.setActorId(this.actorId.toString());
				}
				if (null != this.comment)
				{
					taskInstance.addComment(this.comment);
				}
				if (null != transitionName)
				{
					taskInstance.getContextInstance().setVariable(WFConstants.CURRENT_TRANSITION_NAME, transitionName);
				}
				taskInstance.getContextInstance().setVariable(WFConstants.TASK_PROCESSED, WFConstants.STRING_YES);

				if (null != transitionName && !transitionName.equals(""))
				{
					taskInstance.end(transitionName);
				}
				else
				{
					taskInstance.end();
				}
				jbpmContext.save(taskInstance);

				nextNodeName = taskInstance.getToken().getNode().getName();				
			}
			else
			{
				logger.error("TransProcessInstancebyProcessInstanceCmd.execute() : The current user " + this.actorId
						+ " does not have the permission to perform this action!");
				throw (new Exception("The current user " + this.actorId + " does not have the permission to perform this action"));
			}
		}
		catch (Exception e)
		{
			logger.error("TransProcessInstancebyProcessInstanceCmd.execute() : Error occurred " + e.toString());
			throw (new Exception(e.getMessage(), e));
		}
		return nextNodeName;
	}
}
